from flask import g
from flask import request
from flask import session, render_template, current_app, jsonify
# from project import app  # 直接导入不能取得当前模块的路由地址
from info import db
from info.models import User, News, Category, Comment
from info.utils.response_code import RET
from . import new_views
from info.utils.common import user_landing


@new_views.route("/")
@user_landing
def index():
    # 显示点击数最高的新闻，因为是在index页面上，所以写到index路由上
    # 先从数据库中获取点击次数最高的10条数据，降序排列，放入异常捕获中
    try:
        # 获取到的数据是制定的满足要求的对象
        # news_list = News.query.order_by(News.clicks.desc()).limit(6)
        news_list = News.query.order_by(News.clicks.desc()).limit(8).all()
        # print(type(news_list))
        # print(news_list)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='数据库查询数据失败')
    # 判断是否获取到新闻数据
    if not news_list:
        return jsonify(erron=RET.NODATA, error_info='没有获取到新闻')
    # 定义一个列表存储数据,因为数据是对象的集合，需要遍历这个集合，并将数据格式化输出，将数据返回给浏览器
    list_news = []
    for news in news_list:
        list_news.append(news.to_dict())

    # 显示新闻的分类内容，因为也是在主页面上，所以在访问主页面的同时访问分类路由
    # 获取新闻的分类数据,放入异常捕获中
    try:
        categorys = Category.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='新闻数据查询失败')
    # 判断数据是否存在
    if not categorys:
        return jsonify(erron=RET.NODATA, error_info='没有数据')
    # 定义一个列表存储数据,因为数据是对象的集合，需要遍历这个集合，并将数据格式化输出，将数据返回给浏览器
    cate_list = []
    for category in categorys:
        cate_list.append(category.to_dict())

    # 检查用户登陆状态
    # 使用session对象获取redis数据库中的用户信息
    user_id = session.get('user_id')
    user = None
    data = None
    # 从mysql数据库中取得用户的id以及其他信息，放入捕获异常中
    if user_id:
        try:
            user = User.query.get(user_id)
        except Exception as e:
            current_app.logger.error(e)
            user = None

            # 定义一个字典，用来渲染到前端页面上
    data = {
        # 如果用户存在，将用户的信息存入字典中，返回给前段渲染到页面上
        # user调用to_dict方法得到是一个含有user属性的对象
        'user_info': user.to_dict() if user else None,
        'news_list': list_news,
        'cate_list': cate_list

    }
    return render_template('./news/index.html', data=data)


# 定义一个路由用来获取新闻的列表
@new_views.route('/news_list')
def news_list():
    # 获取每个新闻的分类id，页数，以及每页的数据数
    cate_id = request.args.get('cid', '1')
    page = request.args.get('page', '1')
    per_page = request.args.get('per_page', '10')
    # 确保数据的一致性，将页数和每页数据数转成整数型，放入异常捕获中
    try:
        page, per_page = int(page), int(per_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DATAERR, error_info='数据格式错误')
    # 通过分类id查询所有该分类下的数据并按照新闻的创建时间排序，以及设置每页的数据数
    # 定义一个可以拆包的空列表
    my_list = []
    if cate_id != '1':
        my_list.append(News.category_id == cate_id)

    # 查询数据库中满足分类id的数据，放入异常捕获中
    try:
        page_data = News.query.filter(*my_list).order_by(News.create_time.desc()).paginate(page, per_page, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='查询数据失败')
    # 获取分页后的数据以及总页数和当前页数
    page_info = page_data.items
    # print(page_info)
    total_page = page_data.pages
    current_page = page_data.page
    # print(page_info, total_page, current_page)
    # 定义一个列表，存储查询到分页的数据，返回给前端，渲染在页面上
    page_list = []
    # 遍历分页后的数据，得到每个对象，将对象存入到列表中，并调用对象中固定的方法输出
    for info in page_info:
        page_list.append(info.to_dict())
    # print(page_list)
    # 将所有获取到的数据以字典的形式全部返回给浏览器，渲染到页面上
    data = {
        'page_list': page_list,
        'total_page': total_page,
        'current_page': current_page
    }
    return jsonify(erron=RET.OK, error_info='OK', data=data)


# 定义一个路由，用来展示新闻详情页
@new_views.route('/<int:news_id>')
@user_landing
def news_info(news_id):
    # 根据点击的新闻id在数据库中获取到新闻的信息，放入异常捕获中
    try:
        news_info = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='查询新闻失败')
    # 判断新闻是否存在
    # print(news_info)
    if not news_info:
        return jsonify(erron=RET.NODATA, error_info='新闻不存在')

    # 没点击一次新闻，新闻的点击次数都要加一次,并且操作完之后需要提交到mysql数据库中
    news_info.clicks += 1
    # 提交数据时可能会出现异常，放入异常捕获中
    try:
        db.session.add(news_info)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(erron=RET.DBERR, error_info='数据提交失败')
    # 更新右侧的新闻点击排行
    # 获取点击的新闻信息，放入异常捕获中
    try:
        news_click = News.query.order_by(News.clicks.desc()).limit(6)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='新闻查询失败')
    # 判断新闻是否存在
    if not news_click:
        return jsonify(erron=RET.NODATA, error_info='无新闻数据')
    # 定义一个存储新闻点击排行的列表，将其返回给前端，渲染到新闻详情页
    news_list = []

    # 遍历获取到的新闻，将其存入新的列表中
    for news in news_click:
        news_list.append(news.to_dict())
    # 定义一个评论列表，将新闻的评论渲染到页面上
    comment_list = []
    list = None
    # 从mysql中查询该新闻下所有的评论，放入异常捕获中
    try:
        list = Comment.query.filter(Comment.news_id == news_id).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)
        # return jsonify(erron=RET.DBERR, error_info='评论查询失败')
    # # 判断是否获取到数据
    print(list)
    # if not list:
    #     return jsonify(erron=RET.NODATA, error_info="无评论数据")
    #  遍历获取到所有评论对象，并放入创建的列表中，传入前端页面
    for info in list:
        comment_list.append(info.to_dict())

    # 定义一个用户是否收藏的标记,默认为没有收藏
    is_like = False
    # 　用户登录后，如果收藏的列表中有该新闻，则改变标记的值
    if g.user:
        # print(g.user)
        if news_info in g.user.collection_news:
            # print('123')
            is_like = True
    user = g.user
    # 定义一个字典存储查询到的新闻的信息，返回给前端渲染到页面上
    data = {
        'news': news_info.to_dict(),
        'news_list': news_list,
        'is_like': is_like,
        'user_info': user.to_dict() if user else None,
        'comments': comment_list
    }
    # print(news_dict)
    return render_template('news/detail.html', data=data)


# 定义一个新的路由，用来收藏新闻以及取消收藏新闻
@new_views.route('/news_collectd', methods=['POST'])
@user_landing
def news_collect():
    # url =request.url
    # print(url)
    user = g.user
    # 获取前端传来的参数
    news_id = request.json.get('news_id')
    action = request.json.get('action')
    # print(news_id)
    # 先确定用户是否登录
    if not user:
        return jsonify(erron=RET.SESSIONERR, error_info='用户未登录')
    # 检查参数的完整性
    if not all([news_id, action]):
        return jsonify(erron=RET.PARAMERR, error_info='参数不全')
    # 前端传来的数据可能不是整型，需要转换格式，放图异常捕获中
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.PARAMERR, error_info='参数格式错误')
    # 判断传入的参数是否是在收藏与取消收藏的列表中
    if action not in ['collect', 'cancel_collect']:
        return jsonify(erron=RET.PARAMERR, error_info='参数范围错误')
    # 在数据库中查询是否有该新闻的存在,放入异常捕获中
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='数据库查询失败')
    # 判断数据是否存在
    if not news:
        return jsonify(erron=RET.NODATA, error_info='新闻不存在')
    # 判断用户点击的是哪个，如果点击的是收藏，先要检查用户是否收藏过
    if action == 'collect':
        # print(1111111111111)
        if news not in user.collection_news:
            user.collection_news.append(news)
            print(news)
    # 如果不是收藏，那就是取消收藏
    else:
        # print(2222222222)
        user.collection_news.remove(news)
    # 因为对数据库做了修改，所以必须要提交才能生效，放入异常捕获中
    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='保存数据失败')
    # 成功就可以直接返回成功信息
    return jsonify(erron=RET.OK, error_info='OK')


# 定义一个路由，用来实现用户评论新闻以及评论其他用户的评论
@new_views.route('/news_comment', methods=['POST'])
@user_landing
def news_comment():
    # 获取新闻的id以及用户以及评论的内容以及回复的评论的id
    # 确认参数是否存在
    user = g.user
    if not user:
        return jsonify(erron=RET.SESSIONERR, error_info='用户未登录')
    # 获取其他的参数
    news_id = request.json.get('news_id')
    comment_info = request.json.get('comment')
    parent_id = request.json.get('parent_id')

    # 验证参数的完整性
    if not all([news_id, comment_info]):
        return jsonify(erron=RET.PARAMERR, error_info='参数缺失')
    # 根据新闻id查找mysql数据库中是否存在该新闻，放入异常捕获中
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, error_info='查询新闻失败')
    if not news:
        return jsonify(erron=RET.NODATA, error_info='新闻不存在')
    # 实例化评论对象，将用户的评论保存进评论表中
    comment = Comment()
    comment.user_id = user.id
    comment.news_id = news_id
    comment.content = comment_info
    # 需要判断用户是否评论了其他用户的评论，如果是，将被评论的评论id放入数据库
    if parent_id:
        comment.parent_id = parent_id
    # 对数据库进行了操作，需要提交才能生效，放入异常捕获中
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(erron=RET.DBERR, error_info='评论提交失败')
    # 提交成功后返回评论成功，并将评论的信息返回给前端渲染到页面上
    data = comment.to_dict()
    return jsonify(erron=RET.OK, error_info='评论成功', data=data)


# 加载小图标路由
@new_views.route('/favicon.ico')
def add_icon():
    # 静态文件默认访问 static路径 需要将路由拼接到static下,并返回其地址给浏览器
    return current_app.send_static_file('news/favicon.ico')
